/**
 * @file SimpleCDBUS.cpp
 * @brief SimpleCDBUS Arduino库实现
 * @details 为Arduino平台提供CDBUS协议的完整实现
 *          支持串口通信、数据包收发、地址过滤等功能
 * 
 * @author 修改团队：mastwet@Undefine Innovation
 * @date 2024
 * @copyright MIT License
 * 
 * @note 适用于Arduino UNO、Mega、ESP32等支持HardwareSerial的开发板
 * @note 默认波特率115200，可通过setBaudRate()修改
 * @note 支持最大数据长度：发送255字节，接收255字节
 */

#include "SimpleCDBUS.h"

/**
 * @brief 构造函数
 * @details 初始化SimpleCDBUS对象
 *          设置默认参数：
 *          - 串口指针：NULL（未初始化）
 *          - 地址：0（未设置）
 *          - 初始化标志：false
 *          - 缓冲区清零
 */
SimpleCDBUS::SimpleCDBUS() {
    _serial = NULL;         /* 串口指针初始化为NULL */
    _address = 0;           /* 设备地址初始化为0 */
    _initialized = false;   /* 初始化标志设为false */
    memset(_rx_buffer, 0, sizeof(_rx_buffer));  /* 接收缓冲区清零 */
    memset(_tx_buffer, 0, sizeof(_tx_buffer));  /* 发送缓冲区清零 */
}

/**
 * @brief 初始化CDBUS库
 * @param serial 硬件串口指针（如&Serial、&Serial1等）
 * @param address 本设备的CDBUS地址（0-255）
 * @details 初始化CDBUS协议栈并配置串口通信
 *          设置默认波特率为115200
 * 
 * @note 必须在调用其他函数前调用此函数
 * @note 地址0为广播地址，建议使用1-254
 */
void SimpleCDBUS::begin(HardwareSerial *serial, uint8_t address) {
    _serial = serial;       /* 保存串口指针 */
    _address = address;     /* 保存设备地址 */
    _initialized = true;    /* 设置初始化标志 */
    
    initializeCDBUS();      /* 初始化CDBUS协议栈 */
    
    /* 设置默认波特率115200 */
    _serial->begin(115200);
}

/**
 * @brief 关闭CDBUS库
 * @details 关闭串口通信并重置初始化状态
 *          释放相关资源
 */
void SimpleCDBUS::end() {
    if (_serial) {
        _serial->end();     /* 关闭串口 */
    }
    _initialized = false;   /* 重置初始化标志 */
}

/**
 * @brief 发送数据包
 * @param dst 目标设备地址（0-255）
 * @param data 要发送的数据缓冲区
 * @param len 数据长度（字节数）
 * @details 构造CDBUS数据帧并通过串口发送
 *          自动添加CRC校验和帧头帧尾
 * 
 * @note 数据长度不能超过255字节
 * @note 地址0为广播地址，所有设备都能接收
 */
void SimpleCDBUS::send(uint8_t dst, uint8_t *data, uint8_t len) {
    if (!_initialized || len == 0) return;  /* 检查初始化和数据长度 */
    
    /* 构造CDBUS数据帧 */
    int frame_len = cdbus_create_frame(_address, dst, data, len, _tx_buffer);
    if (frame_len > 0) {
        _serial->write(_tx_buffer, frame_len);  /* 发送数据帧 */
        _serial->flush();  /* 等待发送完成 */
    }
}

/**
 * @brief 读取接收到的数据包
 * @param src 返回源设备地址（可选，传入NULL忽略）
 * @param buffer 接收数据缓冲区
 * @param max_len 缓冲区最大长度
 * @return 实际读取的数据长度（字节数），0表示无数据
 * @details 从接收缓冲区读取一个完整的数据包
 *          自动处理帧解析和CRC校验
 * 
 * @note 需要在available()返回true后调用
 * @note 如果数据长度超过max_len，只返回前max_len字节
 */
uint8_t SimpleCDBUS::read(uint8_t *src, uint8_t *buffer, uint8_t max_len) {
    if (!_initialized) return 0;  /* 检查初始化状态 */
    
    cdbus_frame_t frame;
    if (cdbus_get_frame(&_cdbus, &frame) == 0) {  /* 获取完整帧 */
        if (src) *src = frame.src_addr;  /* 返回源地址 */
        
        /* 计算实际要复制的数据长度 */
        uint8_t copy_len = min(frame.data_len, max_len);
        if (buffer && copy_len > 0) {
            memcpy(buffer, frame.data, copy_len);  /* 复制数据 */
        }
        return copy_len;  /* 返回实际数据长度 */
    }
    
    return 0;  /* 无数据可读取 */
}

/**
 * @brief 检查是否有数据包可读取
 * @return true表示有完整数据包可读取，false表示无数据
 * @details 检查接收缓冲区是否有完整的数据包
 *          自动处理串口数据接收和帧解析
 */
bool SimpleCDBUS::available() {
    if (!_initialized) return false;  /* 检查初始化状态 */
    
    processSerialData();  /* 处理串口数据 */
    return (_cdbus.state == CDBUS_STATE_COMPLETE);  /* 检查是否有完整帧 */
}

/**
 * @brief 设置地址过滤器
 * @param filter 过滤模式（CDBUS_FILTER_*常量）
 * @details 设置接收过滤器，决定接收哪些地址的数据包
 * 
 * @note 可选值：
 *       - CDBUS_FILTER_NONE：接收所有地址
 *       - CDBUS_FILTER_SELF：只接收本机地址
 *       - CDBUS_FILTER_BROADCAST：只接收广播地址
 */
void SimpleCDBUS::setFilter(uint8_t filter) {
    if (!_initialized) return;  /* 检查初始化状态 */
    cdbus_set_filter(&_cdbus, filter);  /* 设置过滤器 */
}

/**
 * @brief 设置串口波特率
 * @param baud 波特率值（如9600、19200、38400、57600、115200等）
 * @details 动态修改串口通信波特率
 * 
 * @note 修改波特率后需要确保所有设备使用相同波特率
 */
void SimpleCDBUS::setBaudRate(uint32_t baud) {
    if (!_initialized || !_serial) return;  /* 检查初始化和串口指针 */
    _serial->begin(baud);  /* 重新初始化串口 */
}

/**
 * @brief 更新状态
 * @details 处理串口接收的数据，更新协议状态机
 *          建议在loop()函数中定期调用
 */
void SimpleCDBUS::update() {
    if (!_initialized) return;  /* 检查初始化状态 */
    processSerialData();  /* 处理串口数据 */
}

/**
 * @brief 初始化CDBUS协议栈
 * @details 内部函数，用于初始化CDBUS协议处理结构
 *          设置设备地址和默认参数
 */
void SimpleCDBUS::initializeCDBUS() {
    cdbus_init(&_cdbus, _address);  /* 初始化协议栈 */
}

/**
 * @brief 处理串口数据
 * @details 内部函数，从串口读取数据并送入协议栈处理
 *          自动处理字节流解析和帧重组
 */
void SimpleCDBUS::processSerialData() {
    /* 处理所有可用的串口数据 */
    while (_serial->available() > 0) {
        uint8_t byte = _serial->read();  /* 读取一个字节 */
        cdbus_process_byte(&_cdbus, byte);  /* 送入协议栈处理 */
    }
}